抽象类

概述

在面向对象编程中,抽象类是一种特殊的类,它不能被实例化,只能被继承。抽象类通常用于定义一组子类的共同行为和属性,但它们本身并不完整,需要子类来实现具体的功能。抽象类可以包含抽象方法,这些方法在抽象类中只有声明而没有实现,具体的实现由子类提供。

为什么使用抽象类?

抽象类的主要用途是提供一个通用的接口或模板,确保所有子类都实现某些特定的方法。这有助于代码的组织和维护,尤其是在处理复杂的继承层次结构时。

抽象类的定义

在 TypeScript 中,抽象类通过 abstract 关键字来定义。抽象类可以包含抽象方法和具体方法。

语法

abstract class AbstractClass {
    abstract abstractMethod(): void; // 抽象方法

    concreteMethod(): void { // 具体方法
        console.log("This is a concrete method.");
    }
}

抽象方法

抽象方法在抽象类中只有声明,没有实现。子类必须实现这些抽象方法。

abstract class Animal {
    abstract makeSound(): void; // 抽象方法

    move(): void { // 具体方法
        console.log("Moving...");
    }
}

具体方法

具体方法在抽象类中有完整的实现,子类可以选择性地覆盖这些方法。

abstract class Animal {
    abstract makeSound(): void; // 抽象方法

    move(): void { // 具体方法
        console.log("Moving...");
    }
}

继承抽象类

子类继承抽象类时,必须实现所有的抽象方法。如果子类没有实现抽象方法,编译器会报错。

class Dog extends Animal {
    makeSound(): void {
        console.log("Woof!");
    }
}

class Cat extends Animal {
    makeSound(): void {
        console.log("Meow!");
    }
}

实例化

抽象类不能被实例化,只能通过子类来实例化。

// 错误示例:不能直接实例化抽象类
// const animal = new Animal(); // 编译错误

// 正确示例:通过子类实例化
const dog = new Dog();
dog.makeSound(); // 输出: Woof!
dog.move(); // 输出: Moving...

const cat = new Cat();
cat.makeSound(); // 输出: Meow!
cat.move(); // 输出: Moving...

实践练习

练习 1:定义一个抽象类 Shape

定义一个抽象类 Shape,包含一个抽象方法 calculateArea() 和一个具体方法 display()。然后创建两个子类 Circle 和 Rectangle,分别实现 calculateArea() 方法。

abstract class Shape {
    abstract calculateArea(): number;

    display(): void {
        console.log(`Area: ${this.calculateArea()}`);
    }
}

class Circle extends Shape {
    constructor(private radius: number) {
        super();
    }

    calculateArea(): number {
        return Math.PI * this.radius ** 2;
    }
}

class Rectangle extends Shape {
    constructor(private width: number, private height: number) {
        super();
    }

    calculateArea(): number {
        return this.width * this.height;
    }
}

const circle = new Circle(5);
circle.display(); // 输出: Area: 78.53981633974483

const rectangle = new Rectangle(4, 6);
rectangle.display(); // 输出: Area: 24

练习 2:定义一个抽象类 Employee

定义一个抽象类 Employee,包含一个抽象方法 calculateSalary() 和一个具体方法 displayInfo()。然后创建两个子类 FullTimeEmployee 和 PartTimeEmployee,分别实现 calculateSalary() 方法。

abstract class Employee {
    constructor(protected name: string, protected id: number) {}

    abstract calculateSalary(): number;

    displayInfo(): void {
        console.log(`Name: ${this.name}, ID: ${this.id}, Salary: ${this.calculateSalary()}`);
    }
}

class FullTimeEmployee extends Employee {
    constructor(name: string, id: number, private monthlySalary: number) {
        super(name, id);
    }

    calculateSalary(): number {
        return this.monthlySalary;
    }
}

class PartTimeEmployee extends Employee {
    constructor(name: string, id: number, private hourlyRate: number, private hoursWorked: number) {
        super(name, id);
    }

    calculateSalary(): number {
        return this.hourlyRate * this.hoursWorked;
    }
}

const fullTimeEmployee = new FullTimeEmployee("John Doe", 1, 5000);
fullTimeEmployee.displayInfo(); // 输出: Name: John Doe, ID: 1, Salary: 5000

const partTimeEmployee = new PartTimeEmployee("Jane Smith", 2, 20, 100);
partTimeEmployee.displayInfo(); // 输出: Name: Jane Smith, ID: 2, Salary: 2000

总结

抽象类是面向对象编程中的一个重要概念,它提供了一种机制来定义通用的接口和模板,确保子类实现特定的方法。通过抽象类,我们可以更好地组织和维护代码,尤其是在处理复杂的继承层次结构时。希望本教程能帮助你理解抽象类的概念和使用方法,并通过实践练习加深理解。